package webTest.upload;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.sql.Date;
import java.util.*;

/**
 * Created by IFT8
 * on 2015/4/30.
 */
public class UploadUtils {
    private static Properties configProperties = new Properties();
    private static Properties mappingProperties = new Properties();

    static {
        try {
            //获取配置信息
            configProperties.load(new FileReader(UploadUtils.class.getClassLoader().getResource("config.properties").getPath()));
            // 获取映射ContentType
            mappingProperties.load(new FileReader(UploadUtils.class.getClassLoader().getResource("fileTypeMapping.properties").getPath()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void in2out(InputStream in, OutputStream out) {
        byte[] buf = new byte[1024 * 1024];
        int len;
        try {
            while ((len = in.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据配置文件允许的文件类型（后缀）
     *
     * @param fileName        文件名
     * @param fileContentType 响应头提供的文件类型
     * @return 是允许的类型返回true
     */
    public static boolean checkFileType(String fileName, String fileContentType) {

        String fileTypeStr = configProperties.getProperty("fileType");
        if (fileTypeStr == null) {
            return true;
        }
        //截取允许的类型
        String[] fileTypes = fileTypeStr.split(";");
        if (fileTypes.length == 0) {
            return true;
        }
        //截取文件名后缀
        int i = fileName.lastIndexOf('.');
        if (i == -1) {
            return false;
        }
        String suffix = fileName.substring(i + 1);

        String contentType = mappingProperties.getProperty(suffix);
        for (String type : fileTypes) {
            if (type.equals(suffix)) {
                if (contentType == null || contentType.equals(fileContentType)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 生成路径
     *
     * @param fileContentType 响应头提供文件类型
     * @return 生成的路径
     */
    public static String makePath(String fileName, String fileContentType) {
        StringBuilder stringBuilder = new StringBuilder();
        //截取文件名后缀(带点)
        int i = fileName.lastIndexOf('.');
        if (i == -1) {
            return null;
        }
        String suffix = fileName.substring(i);
        //截取文件类型(前缀)
        i = fileContentType.lastIndexOf('/');
        if (i == -1) {
            return null;
        }
        String prefix = fileContentType.substring(0, i);
        if ("image".equals(prefix)) {
            stringBuilder.append(configProperties.getProperty("imgPath"));
        } else {
            stringBuilder.append(configProperties.getProperty("videoPath"));
        }
        // 添加下一级/
        if ('/' != stringBuilder.charAt(stringBuilder.length() - 1)) {
            stringBuilder.append('/');
        }
        //现在时间
        Date date = new Date(System.currentTimeMillis());
        stringBuilder.append(date);
        // 添加下一级/
        stringBuilder.append('/');
        //重置文件名
        stringBuilder.append(Integer.toHexString(date.hashCode()));
        stringBuilder.append(Integer.toHexString(fileName.hashCode()));
        //添加后缀
        stringBuilder.append(suffix);
        return stringBuilder.toString();
    }

    /**
     * 上传文件并保存余下信息到Request域
     * @param request 请求
     * @param fieldListMap 字段的Map映射 Map中存放List集合
     * @throws IOException
     */
    public static void Upload(HttpServletRequest request,Map<String,ArrayList<String>> fieldListMap) throws IOException{
        // 1.Apache惯例，工厂类都要new
        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        //设置缓冲区大小为200kb
        diskFileItemFactory.setSizeThreshold(200);
        // 2.文件上传核心类
        ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
        //错误表单格式
        if (!ServletFileUpload.isMultipartContent(request)) {
            throw new RuntimeException("错误的表单格式");
        }
        //设置文件总大小不超过2G
        fileUpload.setSizeMax(1024 * 1024 * 1024 * 2L);
        //设置编码
        fileUpload.setHeaderEncoding("UTF-8");
//        //设置文件监听器
//        fileUpload.setProgressListener(new ProgressListener() {
//            private long begintime = System.currentTimeMillis();
//
//            //bytesRead 已上传字节
//            @Override
//            public void update(long bytesRead, long contentLength, int items) {
//                //--剩余字节
//                long needRead = contentLength - bytesRead;
//                System.out.print("剩余"+needRead+"字节,");
//                //--上传百分比
//                BigDecimal bRead = new BigDecimal(bytesRead);
//                BigDecimal cLength = new BigDecimal(contentLength);
//                BigDecimal per = bRead.multiply(new BigDecimal(100)).divide(cLength,2,BigDecimal.ROUND_HALF_UP);
//                System.out.print("上传百分比"+per+"%,");
//                //--已经用时
//                long time = (System.currentTimeMillis()-begintime)/1000;
//                System.out.print("用时"+time+"秒");
//                //--上传速度
//                if(time != 0){
//                    //bRead/1024/time (KB/秒)
//                    BigDecimal speed = bRead.divide(new BigDecimal(1024)).divide(new BigDecimal(time),2,BigDecimal.ROUND_HALF_UP);
//                    System.out.print("上传速度:"+speed+"KB/S");
//                }
//                //--大概剩余时间
//                System.out.println();
//            }
//        });
        // 3.获取文件列表
        try {
//            List<FileItem> fileItems = fileUpload.parseRequest(request);//过时方法
            List<FileItem> fileItems = fileUpload.parseRequest(new ServletRequestContext(request));
            // 4.遍历出上传信息
            for (FileItem fileItem : fileItems) {
                // 不是文件 是字段
                if (fileItem.isFormField()) {
                    // fileItem.getFieldName()获取字段名 fileItem.getString("UTF-8")以UTF-8获取字段值
                    ArrayList<String> fieldValues = fieldListMap.get(fileItem.getFieldName());
                    if (fieldValues!=null){
                        fieldValues.add(fileItem.getString("UTF-8"));
                    }
                }else{
                    //大小为0不上传
                    if(fileItem.getSize()==0){
                        continue;
                    }
                    //检查文件类型
                    boolean isAllow = checkFileType(fileItem.getName(), fileItem.getContentType());
                    if (!isAllow){
                        throw new RuntimeException("不允许的文件类型");
                    }
                    //获取文件流
                    InputStream in = fileItem.getInputStream();
                    //输出流
//                    ServletOutputStream out = response.getOutputStream();
                    String fileName = fileItem.getName();
                    //为了兼容IE6 (IE6会把整个路径当成文件名)
                    fileName = fileName.substring(fileName.lastIndexOf('\\') + 1);
                    String path = makePath(fileName, fileItem.getContentType());
                    //真实上传路径
                    File file = new File(request.getServletContext().getRealPath(path));
                    //不管有没有上级路径尝试生成
                    file.getParentFile().mkdirs();
                    FileOutputStream out=new FileOutputStream(file);
                    //写出
                    in2out(in, out);
                    out.close();
                    //删除临时文件
                    fileItem.delete();
                    /*路径保存到Request域，让下一个Servlet处理*/
                    //截取文件类型(前缀)
                    int i = fileItem.getContentType().lastIndexOf('/');
                    if (i == -1) {
                        continue;
                    }
                    String prefix = fileItem.getContentType().substring(0, i);
                    ArrayList<String> fieldValues;
                    if ("image".equals(prefix)){
                        fieldValues = fieldListMap.get("imgs");
                        if (fieldValues!=null){
                            fieldValues.add(path);
                        }
                    }else{
                        fieldValues = fieldListMap.get("urls");
                        if (fieldValues!=null){
                            fieldValues.add(path);
                        }
                    }
                }
            }
//            //信息存入Request域
//            for (Map.Entry<String, ArrayList<String>> entry : fieldListMap.entrySet()) {
//                request.setAttribute(entry.getKey(),entry.getValue());
//            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据字段List生成ListMap
     * @param fieldList 存放着字段的List
     * @return 返回初始化好的ListMap
     */
    public static Map<String,ArrayList<String>> initListMap(List<String> fieldList){
        Map<String,ArrayList<String>> listMap=new HashMap<String, ArrayList<String>>();
        //字段存入Map中
        for (String s : fieldList) {
            listMap.put(s,new ArrayList<String>());
        }
        return listMap;
    }
}
